

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Random;


public class Ant implements defAnt {

	//Fields
	public static final int NOFOOD = 16;
	public static final int GOTFOOD = 50;
//	public static enum DIRECTION { leftBottomLeft, left, rightTopRight, right, leftTopTop, top, rightBottomBottom, bottom, leftTopLeft, leftTop, leftBottomBottom,
//		leftBottom, rightTopTop, rightTop, rightBottomRight, rightBottom };//Reihenfolge wichtig!!!!
//	public static final DIRECTION [] defaultPrefDir = { DIRECTION.leftBottomLeft, DIRECTION.left, DIRECTION.rightTopRight, DIRECTION.right, DIRECTION.leftTopTop, DIRECTION.top, DIRECTION.rightBottomBottom, DIRECTION.bottom, DIRECTION.leftTopLeft, DIRECTION.leftTop, DIRECTION.leftBottomBottom, DIRECTION.leftBottom, DIRECTION.rightTopTop, DIRECTION.rightTop, DIRECTION.rightBottomRight, DIRECTION.rightBottom };
//	private static final int [] dirActions = { 13, 12, 31, 32, 11, 21, 33, 23, 12, 11, 23, 13, 21, 31, 32, 33 };
	public static enum DIRECTION { leftBottomLeft, left, leftTopLeft, leftTop, leftTopTop, top, rightTopTop, rightTop, rightTopRight, right, rightBottomRight, rightBottom, rightBottomBottom,
		bottom, leftBottomBottom, leftBottom };//Reihenfolge wichtig!!!!
	public static final DIRECTION [] defaultPrefDir = { DIRECTION.leftBottomLeft, DIRECTION.left, DIRECTION.leftTopLeft, DIRECTION.leftTop, DIRECTION.leftTopTop, DIRECTION.top, DIRECTION.rightTopTop, DIRECTION.rightTop, DIRECTION.rightTopRight, DIRECTION.right, DIRECTION.rightBottomRight, DIRECTION.rightBottom, DIRECTION.rightBottomBottom,
		DIRECTION.bottom, DIRECTION.leftBottomBottom, DIRECTION.leftBottom };
	private static final int [] dirActions = { 13, 12, 12, 11, 11, 21, 21, 31, 31, 32, 32, 33, 33, 23, 23, 13 };
	// 1.Stelle: x-Coordinate, 1->-1, 2->0, 3->1;
	// 2.Stelle: y-Coordinate, 1->-1, 2->0, 3->1.
		
	private static Random rand = new Random();
	private static  int exactMod;
	private static final int waitConstant = 0;
	
	
	
	//Attributes
	
	private int counter;
	private Point position;
	private PTrail pTrail;
	public int food = NOFOOD;
	private DIRECTION [] prefDir;
	private boolean secondDirectionChosen = false;
	private DIRECTION beforeLastDir;
	private int angleWay = 0;
//	private int waiter = 0;
	private Point equalPosition = new Point(0,0);
	private boolean following = true;
	
	private AntSimulation antSim;
		
	
	//Constructor
	public Ant( Point p ,AntSimulation as){
		antSim=as;
				
		position = new Point( p );
		prefDir = defaultPrefDir.clone();
		antSim.getForestground()[p.x][p.y] *= -1;
		counter=0;
		exactMod = antSim.anthill_rectangle.size/3;
	}
	
	
	public Ant( Point p, DIRECTION dir ,AntSimulation as){
		antSim=as;
		
		position = new Point( p );
		prefDir = defaultPrefDir.clone();
		for(int i=0; i<16; i++){
			changeOrder(defaultPrefDir[rand.nextInt(defaultPrefDir.length)]);
		}
		changeOrder( dir );
		antSim.getForestground()[p.x][p.y] *= -1;
		pTrail = new PheromoneTrail(antSim);
		beforeLastDir = prefDir[15];
		exactMod = antSim.anthill_rectangle.size/3;
		
		counter=0;
	}
	
	
	/*
	Methods
	*/
	
	//getter - Methods
	
	public int getX(){
		return this.position.x;
	}
	
	public int getY(){
		return this.position.y;
	}
	
	public int getFood(){
		return this.food;
	}
	
	public PTrail getPtrail(){
		return (PheromoneTrail) this.pTrail;
	}
	
	// other Methods

	private void changeOrder( DIRECTION dir ){
		DIRECTION saveDir = dir, tmpDir = prefDir[0];
		int i = 0;
		while( prefDir[i] != dir ){
			tmpDir = prefDir[i];
			prefDir[i] = saveDir;
			saveDir = tmpDir;
			i++;
		}
		prefDir[i] = tmpDir;
		//return prefDir[0].name();
	}
	
	private void sendToBack( DIRECTION dir ){
		DIRECTION saveDir, tmpDir = dir;
		int i = prefDir.length-1;
		while( prefDir[i] != dir ){
			saveDir = prefDir[i];
			prefDir[i] = tmpDir;
			tmpDir = saveDir;
			i--;
		}
		prefDir[i] = tmpDir;
	}
	
	//version one -> 4 main doors
	private void goHome(Point nextPoint){
		int xdiff = nextPoint.x - position.x;
		int ydiff = nextPoint.y - position.y;
		double quot = Math.abs((double)ydiff / (double)xdiff);
		
		//x==0
		if(Math.abs(xdiff)<exactMod){
			if(ydiff<0)
				changeOrder(DIRECTION.top);
			else
				changeOrder(DIRECTION.bottom);
		//x>0
		} else if(xdiff>0){
			if(Math.abs(ydiff)<exactMod){
				changeOrder(DIRECTION.right);
			} else if(ydiff>0){
				if(quot>1.25)
					changeOrder(DIRECTION.rightBottomBottom);
				else if(quot<0.75)
					changeOrder(DIRECTION.rightBottomRight);
				else
					changeOrder(DIRECTION.rightBottom);
			} else if(ydiff<0){
				if(quot>1.25)
					changeOrder(DIRECTION.rightTopTop);
				else if(quot<0.75)
					changeOrder(DIRECTION.rightTopRight);
				else
					changeOrder(DIRECTION.rightTop);
			} 
		//x<0
		} else if(xdiff<0){ 
			if(Math.abs(ydiff)<exactMod){
				changeOrder(DIRECTION.left);
			} else if(ydiff>0){
				if(quot>1.25)
					changeOrder(DIRECTION.leftBottomBottom);
				else if(quot<0.75)
					changeOrder(DIRECTION.leftBottomLeft);
				else
					changeOrder(DIRECTION.leftBottom);
			} else if(ydiff<0){
				if(quot>1.25)
					changeOrder(DIRECTION.leftTopTop);
				else if(quot<0.75)
					changeOrder(DIRECTION.leftTopLeft);
				else
					changeOrder(DIRECTION.leftTop);
			}
		}
	}//goHome()
	
	private boolean stepDirection( Point nextPoint ){
		
		counter++;
		if( counter%50==0 && this.food==GOTFOOD ){
			goHome( antSim.anthill_rectangle.getMidPoint() );
			counter=0;
			secondDirectionChosen=false;
		}
		
		if( counter%10==0 ){
			if( following ){
				if( Math.abs(position.x-equalPosition.x) < 5 && Math.abs(position.y-equalPosition.y) < 5 ){
					following = false;
				}
			} else
				following = true;
			equalPosition = new Point( position );
		}
		
		if( following && counter%1==0 && this.food == NOFOOD ){
			int aktPheromone = antSim.getForestground()[position.x][position.y];
			int borderPheromone = 30;
			borderPheromone = Math.max( borderPheromone, aktPheromone );
			int maxPheromone = borderPheromone;
			int rangeAngle = 5;
			DIRECTION actDirection = prefDir[0]; 
			for( int i = rangeAngle-1; i >= 0; i-- ){
				int action = Ant.dirActions[ (actDirection.ordinal() + i )%16 ];
				int akty = position.y + action%10 - 2;//xdiff;
				action/=10;
				int aktx = position.x + action - 2;//ydiff;
				if( aktx >= 0 && aktx < antSim.getSimWidth() && akty >= 0 
						&& akty < antSim.getSimHeight() 
						&& antSim.getForestground()[aktx][akty] > borderPheromone ){
					changeOrder( Ant.defaultPrefDir[ (actDirection.ordinal() + i)%16 ] );
					if( antSim.getForestground()[aktx][akty] > maxPheromone )
						maxPheromone = antSim.getForestground()[aktx][akty];
					else
						changeOrder( prefDir[1] );
					secondDirectionChosen = false;
//					break; //i runter oder hochzaehlen
				}
				action = Ant.dirActions[ (actDirection.ordinal() - i + 16)%16 ];
				akty = position.y + action%10 - 2;//xdiff;
				action/=10;
				aktx = position.x + action - 2;//ydiff;
				if( aktx >= 0 && aktx < antSim.getSimWidth() && akty >= 0 
						&& akty < antSim.getSimHeight() 
						&& antSim.getForestground()[aktx][akty] > borderPheromone ){
					changeOrder( Ant.defaultPrefDir[ (actDirection.ordinal() - i + 16)%16 ] );
					if( antSim.getForestground()[aktx][akty] > maxPheromone )
						maxPheromone = antSim.getForestground()[aktx][akty];
					else
						changeOrder( prefDir[1] );
					secondDirectionChosen = false;
//					break; //i runter oder hochzaehlen
				}
			}
		}
		
		
		for( int i = 0; i < prefDir.length; i++ ){
	
			DIRECTION secDir = prefDir[1];
			if( i > 1 )
				secondDirectionChosen = false;
			DIRECTION actDir = prefDir[i];
			
			if( i > 0 && actDir == beforeLastDir )
				continue;
			if( actDir == Ant.defaultPrefDir[ (prefDir[0].ordinal() + 8)%16 ]){
				actDir = Ant.defaultPrefDir[ (prefDir[0].ordinal() + (int)Math.pow(-1, rand.nextInt(1))*angleWay++ + 16 )%16 ];
				sendToBack(prefDir[0]);
			}
			
			int action = Ant.dirActions[ actDir.ordinal() ];
			if( actDir.ordinal()%2 == 0 ){
				secondDirectionChosen = true;
				secDir = Ant.defaultPrefDir[ actDir.ordinal() + 1 ];
			}
			
			int akty = nextPoint.y + action%10 - 2;//xdiff;
			action/=10;
			int aktx = nextPoint.x + action - 2;//ydiff;
			
			if( aktx >= 0 && aktx < antSim.getSimWidth() && akty >= 0 
					&& akty < antSim.getSimHeight() ){
				if( antSim.getForestground()[aktx][akty] > 0 ){
					nextPoint.x = aktx;
					nextPoint.y = akty;
					if( i > 0 )
						beforeLastDir = prefDir[0];
					changeOrder( prefDir[i] );
					if( secondDirectionChosen ){
						changeOrder( secDir );
					}
					return true;
//				} else if( antSim.getForestground()[aktx][akty] < 0 /*&& antSim.getForestground()[aktx][akty] > -250*/ ){
//					if( waiter <= waitConstant ){
//						waiter++;
//						return false;
//					} else {
//						waiter = 0;
//					}
				}
			}
			
			if( aktx > 0 && aktx < antSim.getSimWidth() 
					&& akty > 0 && akty < antSim.getSimHeight() 
					&& antSim.getForestground()[aktx][akty] < -255 && this.food == NOFOOD ){
				this.food = GOTFOOD;
				antSim.getForestground()[aktx][akty] += GOTFOOD;
				
				if( antSim.getForestground()[aktx][akty] >= -255 )
					antSim.getForestground()[aktx][akty] = 1;
				return false;
			}
			//wenn die Ameisen am Huegel angekommen sind, geben sie das Futter ab
			if(antSim.anthill_rectangle.isAtBorder(aktx, akty) )
				this.food = NOFOOD;
		}
		return false;
	}

	
	private void validatePheromoneTrail(){
		pTrail.validate( position, this.food );
	}
	
	
	public void draw( Graphics g ){
		Color tmp;
		if( food == GOTFOOD )
			tmp = Color.red;
		else
			tmp = Color.black;
//		g.setColor(tmp);
//		g.fillRect( position.x, position.y, 1, 1);
		antSim.setUnderlayerColor(position.x, position.y, tmp.getRGB());
	}

	
	public void drawTrail( Graphics g ){
		pTrail.draw( g );
	}
	
	
	public void stepForward(){
		Point nextPoint = new Point( position );
		if( this.stepDirection( nextPoint ) ){
			angleWay = 0;
			antSim.getForestground()[position.x][position.y] *= -1;
			antSim.getForestground()[nextPoint.x][nextPoint.y] *= -1;
			position = nextPoint;
			validatePheromoneTrail();
		
		}
	}


	
	
}
